/**
 * 
 */
package com.example.android.opengl;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import android.content.Context;
import android.opengl.GLES20;

import com.example.android.opengl.R.raw;
import com.example.android.opengl.utils.RawResourceReader;
import com.example.android.opengl.utils.TextureHelper;

/**
 * @author Hitechworm
 *
 */
//@FOFF
public class GLRippleBitmap {	// @FON
	private static float[]	texCoords;
	private static float[]	vertices;

	private int				mProgram;

	private int				bitmapTextureId;

	private int				iPositionProgramRipple;

	private int				iTexCoordsProgramRipple;

	private int				iMatrixProgramRipple;

	private int				iTimeProgramRipple;

	private FloatBuffer		vertexBuffer;

	private FloatBuffer		texCoordsBuffer;

	private int				surfaceWidth;

	private int				surfaceHeight;

	private int				imageWidth;

	private int				imageHeight;

	private int				widthNpot;

	private int				heightNpot;

	private long			beginTime;

	public GLRippleBitmap(Context context, int res) {

		beginTime = System.currentTimeMillis();

		int[] outSize = new int[2];
		bitmapTextureId = TextureHelper.loadTexture(context, res, outSize);

		imageWidth = outSize[0];
		imageHeight = outSize[1];
		if (MyGLRenderer.nPot) {
			widthNpot = imageWidth;
			heightNpot = imageHeight;
		} else {
			int w2 = nextPowerOf2(imageWidth);
			int h2 = nextPowerOf2(imageHeight);
			widthNpot = w2;
			heightNpot = h2;
		}

		vertices = new float[1 * 4 * 2];
		texCoords = new float[1 * 4 * 2];

		vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4)
				.order(ByteOrder.nativeOrder()).asFloatBuffer();
		texCoordsBuffer = ByteBuffer.allocateDirect(texCoords.length * 4)
				.order(ByteOrder.nativeOrder()).asFloatBuffer();

		// prepare shaders and OpenGL program
		mProgram = GLES20.glCreateProgram();

		String strVShader = RawResourceReader.readTextFileFromRawResource(
				context, raw.basic_vertext);
		String strFShader = RawResourceReader.readTextFileFromRawResource(
				context, raw.ripples_fragment);

		GLES20.glAttachShader(mProgram,
				MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, strVShader));
		GLES20.glAttachShader(mProgram,
				MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, strFShader));

		GLES20.glLinkProgram(mProgram); // create OpenGL program executables

		//
		iPositionProgramRipple = GLES20.glGetAttribLocation(mProgram,
				"a_Position");
		iTexCoordsProgramRipple = GLES20.glGetAttribLocation(mProgram,
				"a_TexCoords");
		iMatrixProgramRipple = GLES20
				.glGetUniformLocation(mProgram, "u_Matrix");
		iTimeProgramRipple = GLES20.glGetUniformLocation(mProgram, "uTime");
	}

	public static int nextPowerOf2(int i) {
		double d = log2(i);
		double a = d - (int) d;
		if (a > 0) {
			d++;
			return (int) Math.pow(2, (int) d);
		}
		return (int) Math.pow(2, (int) d);
	}

	public static double logb(double a, double b) {
		return Math.log(a) / Math.log(b);
	}

	public static double log2(double a) {
		return logb(a, 2);
	}

	public void onSurfaceChanged(int width, int height) {
		this.surfaceWidth = width;
		this.surfaceHeight = height;
		buildBuffer();
	}

	public void draw(float[] mMVPMatrix) {
		GLES20.glUseProgram(mProgram);

		//
		GLES20.glEnableVertexAttribArray(iPositionProgramRipple);
		GLES20.glVertexAttribPointer(iPositionProgramRipple, 2,
				GLES20.GL_FLOAT, false, 0, vertexBuffer);
		GLES20.glEnableVertexAttribArray(iTexCoordsProgramRipple);
		GLES20.glVertexAttribPointer(iTexCoordsProgramRipple, 2,
				GLES20.GL_FLOAT, false, 0, texCoordsBuffer);
		GLES20.glUniformMatrix4fv(iMatrixProgramRipple, 1, false, mMVPMatrix, 0);
		float time = (System.currentTimeMillis() - beginTime) / 1000f;
		GLES20.glUniform1f(iTimeProgramRipple, time);

		//
		GLES20.glEnable(GLES20.GL_BLEND);
		GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, bitmapTextureId);
		GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
		//
		GLES20.glDisableVertexAttribArray(iPositionProgramRipple);
		GLES20.glDisableVertexAttribArray(iTexCoordsProgramRipple);
		GLES20.glDisable(GLES20.GL_BLEND);
	}

	private void buildBuffer() {

		float xcenter = surfaceWidth / 2f;
		float ycenter = surfaceHeight / 2f;
		float hW = surfaceWidth / 2f;
		float hH = surfaceHeight / 2f;

		float imageRatio = (float) imageWidth / (float) imageHeight;
		float viewRatio = (float) surfaceWidth / (float) surfaceHeight;

		if (imageRatio > viewRatio) {
			hW = hH * imageRatio;
		} else {
			hH = hW / imageRatio;
		}

		texCoords[0] = texCoords[4] = 0;
		texCoords[1] = texCoords[3] = imageHeight / heightNpot;
		texCoords[2] = texCoords[6] = imageWidth / widthNpot;
		texCoords[5] = texCoords[7] = 0;

		vertices[0] = xcenter - hW;
		vertices[1] = ycenter + hH;
		vertices[2] = xcenter + hW;
		vertices[3] = ycenter + hH;
		vertices[4] = xcenter - hW;
		vertices[5] = ycenter - hH;
		vertices[6] = xcenter + hW;
		vertices[7] = ycenter - hH;

		vertexBuffer.clear();
		vertexBuffer.put(vertices).position(0);

		texCoordsBuffer.clear();
		texCoordsBuffer.put(texCoords).position(0);
	}
}
